package com.example.geoaimavlink_android.activity.fragment

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageFormat
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.YuvImage
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.geoaimavlink_android.R
import com.example.geoaimavlink_android.activity.utils.YUVUtil
import com.example.geoaimavlink_android.activity.view.FilePickerFullScreen
import com.geoai.mavlink.geoainet.obstacle.enums.ObstacleCalibrationSource
import com.geoai.mavlink.geoainet.obstacle.enums.ObstacleCameraSource
import com.geoai.video.VideoFeederView4
import com.geoai.video.YFVParams
import com.github.gzuliyujiang.filepicker.ExplorerConfig
import com.github.gzuliyujiang.filepicker.annotation.ExplorerMode
import com.libyuv.util.YuvUtil
import kotlinx.android.synthetic.main.frag_vision_calibration.btn_release
import kotlinx.android.synthetic.main.frag_vision_calibration.btn_select_obs_file
import kotlinx.android.synthetic.main.frag_vision_calibration.btn_start_calibration
import kotlinx.android.synthetic.main.frag_vision_calibration.btn_start_video
import kotlinx.android.synthetic.main.frag_vision_calibration.btn_switch_camera
import kotlinx.android.synthetic.main.frag_vision_calibration.btn_upload_obs_file
import kotlinx.android.synthetic.main.frag_vision_calibration.img_result
import kotlinx.android.synthetic.main.frag_vision_calibration.tv_camera_source
import kotlinx.android.synthetic.main.frag_vision_calibration.tv_log_path
import kotlinx.android.synthetic.main.frag_vision_calibration.video_feeder
import java.io.ByteArrayOutputStream
import java.io.File
import java.util.concurrent.atomic.AtomicBoolean


class VisionCalibrationFragment : BaseFragment() {

    private val isCalibrationRegistered = AtomicBoolean(false)

    private val isThreadRun = AtomicBoolean(false)

    private val retData by lazy { ByteArray(6000000) }//随便申请的空间

    private var sourceIndex = 2

    private var obsFiles = ""

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return View.inflate(context, R.layout.frag_vision_calibration, null)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView()
    }

    private fun initThread() {
        if (isThreadRun.compareAndSet(false, true)) {
            Thread {
                while (isThreadRun.get()) {
                    //没有注册
                    if (isCalibrationRegistered.get().not()) {
                        continue
                    }
                    val bitmap = video_feeder.bitmap ?: continue
                    val newBitmap = getResizedBitmap(bitmap, 1024, 384)
                    val width = newBitmap.width
                    val height = newBitmap.height

                    val nv21 = YUVUtil.fetchNV21(newBitmap)

                    val i420 = ByteArray(width * height * 2)
                    YuvUtil.yuvNV21ToI420(nv21, width, height, i420)

                    val yv12 = ByteArray(width * height * 2)
                    YuvUtil.yuvI420ToYV12(i420, width, height, width, yv12)

                    val ret = getProduct()?.obstacleManager?.startObstacleCalibration(
                        yv12,
                        retData,
                        width,
                        height
                    )

                    val i420R = ByteArray(width * height * 2)
                    YuvUtil.yuvYV12ToI420(retData, width, height, i420R)

                    val nv21R = ByteArray(width * height * 2)
                    YuvUtil.yuvI420ToNV21(i420R, width, height, nv21R)

                    val yuvImage = YuvImage(nv21R, ImageFormat.NV21, width, height, null)
                    val outputStream = ByteArrayOutputStream()
                    yuvImage.compressToJpeg(Rect(0, 0, width, height), 100, outputStream)
                    val array = outputStream.toByteArray()

                    bitmap.recycle()
                    newBitmap.recycle()

                    mainHandler.post {
                        img_result?.setImageBitmap(
                            BitmapFactory.decodeByteArray(
                                array,
                                0,
                                array.size
                            )
                        )
                    }
                }
            }.start()
        }
    }

    private fun initView() {
        btn_release.setOnClickListener {
            isThreadRun.set(false)
            isCalibrationRegistered.set(false)
            btn_switch_camera.isEnabled = true
            btn_start_video.isEnabled = true
            getProduct()?.obstacleManager?.releaseObstacleCalibration()
        }

        btn_switch_camera.setOnClickListener {
            if (sourceIndex > ObstacleCameraSource.values().size - 2) sourceIndex = 2//without all and fpv
            tv_camera_source?.text = ObstacleCameraSource.values()[sourceIndex].name
            getProduct()?.obstacleManager?.setObstacleCameraSource(ObstacleCameraSource.values()[sourceIndex]) {
                showToast(it?.description ?: "success")
                if (it == null) {
                    btn_start_video.isEnabled = true
                }
            }
            sourceIndex++
        }

        btn_start_video.setOnClickListener {
            getProduct()?.obstacleManager?.setObstacleCameraSource(ObstacleCameraSource.OBSTACLE_CAMERA_FRONT) { geoaiError ->
                if (geoaiError == null) {
                    startPlayer()
                } else {
                    showToast("error: ${geoaiError.description}")
                }
            }
        }

        btn_start_calibration.setOnClickListener {
            val path = requireActivity().getExternalFilesDir(null)!!.path + File.separator + tv_camera_source?.text + "_" + System.currentTimeMillis() + ".vc"
            val retCode = getProduct()?.obstacleManager?.initObstacleCalibrationLibrary(path, 20.0f, 2000)
            if (!isCalibrationRegistered.get()) {
                //没有注册过
                isCalibrationRegistered.set(true)
                btn_switch_camera.isEnabled = false
                btn_start_video.isEnabled = false
                initThread()
                tv_log_path?.text = path
                showToast("success")
            }
        }

        btn_select_obs_file.setOnClickListener {
            FilePickerFullScreen(requireActivity()).apply {
                setExplorerConfig(ExplorerConfig(context).apply {
                    rootDir = context.getExternalFilesDir(null)
                    isLoadAsync = false
                    explorerMode = ExplorerMode.FILE
                    setOnFilePickedListener {
                        obsFiles = it.absolutePath
                    }
                })
                show()
            }
        }

        btn_upload_obs_file.setOnClickListener {
            try {
                val ocs = when(ObstacleCameraSource.valueOf(tv_camera_source?.text.toString())) {
                    ObstacleCameraSource.OBSTACLE_CAMERA_FRONT -> ObstacleCalibrationSource.OBSTACLE_CAMERA_FRONT
                    ObstacleCameraSource.OBSTACLE_CAMERA_TAIL -> ObstacleCalibrationSource.OBSTACLE_CAMERA_TAIL
                    ObstacleCameraSource.OBSTACLE_CAMERA_LEFT -> ObstacleCalibrationSource.OBSTACLE_CAMERA_LEFT
                    ObstacleCameraSource.OBSTACLE_CAMERA_RIGHT -> ObstacleCalibrationSource.OBSTACLE_CAMERA_RIGHT
                    ObstacleCameraSource.OBSTACLE_CAMERA_UP -> ObstacleCalibrationSource.OBSTACLE_CAMERA_UP
                    ObstacleCameraSource.OBSTACLE_CAMERA_DOWN -> ObstacleCalibrationSource.OBSTACLE_CAMERA_DOWN
                    else -> {ObstacleCalibrationSource.OBSTACLE_CAMERA_FRONT}
                }
                getProduct()?.obstacleManager?.uploadObstacleCalibrationFile(ocs, obsFiles) {
                    showToast(it?.description?:"success")
                }
            } catch (e: Exception) {
                showToast("error: ${e.message}")
            }
        }
    }

    private fun startPlayer() {
        video_feeder.initPlayer(
            YFVParams.Builder()
                .setPlayNode(VideoFeederView4.PlayNode.VISION_CALIBRATION)
                .setVideoCodecMode(VideoFeederView4.CodecMode.HARDWARE)
                .setVideoDecodeMode(VideoFeederView4.DecodeMode.H265)
                .setSurfaceMode(VideoFeederView4.SurfaceMode.TEXTURE)
                .build(), VideoFeederView4::startPlayer
        )
    }

    override fun onDestroyView() {
        isThreadRun.set(false)
        super.onDestroyView()
    }

    private fun getResizedBitmap(bm: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
        val width = bm.width
        val height = bm.height
        val scaleWidth = newWidth.toFloat() / width
        val scaleHeight = newHeight.toFloat() / height
        // CREATE A MATRIX FOR THE MANIPULATION
        val matrix = Matrix()
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight)

        // "RECREATE" THE NEW BITMAP
        val resizedBitmap = Bitmap.createBitmap(
            bm, 0, 0, width, height, matrix, false
        )
        bm.recycle()
        return resizedBitmap
    }
}